#![no_std]
#![no_main]
#![feature(abi_x86_interrupt)]
#![feature(allocator_api)]
#![feature(let_chains)]
#![feature(naked_functions)]
#![feature(vec_into_raw_parts)]
#![allow(dead_code)]
#![allow(static_mut_refs)]

use core::sync::atomic::AtomicBool;

use process::{get_current_process, get_current_thread, process::Process};

extern crate alloc;

#[macro_use]
extern crate log;

pub static START_SCHEDULE: AtomicBool = AtomicBool::new(false);

pub fn init() {
    memory::init_heap();

    klog::init();

    info!("React OS starting...");

    arch::smp::CPUS.write().init_bsp();

    arch::interrupts::IDT.load();

    arch::smp::CPUS.write().init_ap();

    arch::apic::init();

    arch::interrupts::init();

    syscall::init();

    arch::sse::init();

    process::init();

    device::init();

    fs::init();

    Process::new_user_process("init", "/root/init.elf", 0, 0, 0).unwrap();

    START_SCHEDULE.store(true, core::sync::atomic::Ordering::SeqCst);
}

pub fn addr_of<T>(reffer: &T) -> usize {
    reffer as *const T as usize
}

pub fn ref_to_mut<T>(reffer: &T) -> &mut T {
    unsafe { &mut *(addr_of(reffer) as *const T as *mut T) }
}

pub fn ref_to_static<T>(reffer: &T) -> &'static T {
    unsafe { &*(addr_of(reffer) as *const T) }
}

#[macro_export]
macro_rules! unsafe_trait_impl {
    ($struct: ident, $trait: ident) => {
        unsafe impl $trait for $struct {}
    };
    ($struct: ident, $trait: ident, $life: tt) => {
        unsafe impl<$life> $trait for $struct<$life> {}
    };
}

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    error!("{}", info);

    let tid = get_current_thread().read().id;
    info!("[PANIC] exit: {}", tid.0);

    let proc = get_current_process();
    proc.write()
        .threads
        .retain(|thread| thread.read().id != tid);

    if proc.read().threads.len() == 0 {
        proc.read().exit_process();
    }

    loop {
        x86_64::instructions::interrupts::enable_and_hlt();
    }
}

pub mod arch;
pub mod device;
pub mod display;
pub mod fs;
pub mod klog;
pub mod memory;
pub mod process;
pub mod serial;
pub mod syscall;
pub mod terminal;
